"""
病历质量评估引擎
实现基于规则的评估逻辑
"""
from typing import Dict, Any, List, Tuple
from app.schemas.assessment import IssueType, IssueSeverity, DimensionWeights
from app.core.logger import app_logger
import re


class QualityEvaluator:
    """病历质量评估器"""
    
    def __init__(self, weights: DimensionWeights = None):
        """
        初始化评估器
        
        Args:
            weights: 自定义权重，不提供则使用默认值
        """
        self.weights = weights or DimensionWeights()
    
    def evaluate(self, record_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        执行完整评估
        
        Args:
            record_data: 病历数据（包含 raw_data）
            
        Returns:
            评估结果字典
        """
        app_logger.info(f"开始评估病历: {record_data.get('patient_name')}")
        
        # 各维度评估
        completeness_result = self._evaluate_completeness(record_data)
        standardization_result = self._evaluate_standardization(record_data)
        consistency_result = self._evaluate_consistency(record_data)
        accuracy_result = self._evaluate_accuracy(record_data)
        
        # 计算综合得分
        overall_score = self._calculate_overall_score(
            completeness_result['score'],
            standardization_result['score'],
            consistency_result['score'],
            accuracy_result['score']
        )
        
        # 合并所有问题
        all_issues = (
            completeness_result['issues'] +
            standardization_result['issues'] +
            consistency_result['issues'] +
            accuracy_result['issues']
        )
        
        # 生成总结和建议
        summary = self._generate_summary(overall_score, all_issues)
        suggestions = self._generate_suggestions(all_issues)
        
        result = {
            'overall_score': overall_score,
            'completeness_score': completeness_result['score'],
            'standardization_score': standardization_result['score'],
            'consistency_score': consistency_result['score'],
            'accuracy_score': accuracy_result['score'],
            'issues': all_issues,
            'summary': summary,
            'suggestions': suggestions
        }
        
        app_logger.info(f"评估完成，综合得分: {overall_score}")
        return result
    
    def _calculate_overall_score(self, comp: int, std: int, cons: int, acc: int) -> int:
        """计算综合得分"""
        score = (
            comp * self.weights.completeness +
            std * self.weights.standardization +
            cons * self.weights.consistency +
            acc * self.weights.accuracy
        )
        return int(round(score))
    
    def _evaluate_completeness(self, record_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        评估完整性（30%权重）
        检查必填字段是否完整
        """
        issues = []
        score = 100
        
        # 必填字段定义
        required_fields = {
            'patient_name': ('患者姓名', 10),
            'chief_complaint': ('主诉', 8),
            'present_illness': ('现病史', 10),
            'physical_exam': ('体格检查', 10),
            'diagnosis': ('诊断', 12),
            'allergy_history': ('过敏史', 5),
            'past_history': ('既往史', 5),
        }
        
        # 重要字段
        important_fields = {
            'patient_age': ('患者年龄', 5),
            'patient_gender': ('患者性别', 5),
            'department': ('科室', 5),
            'visit_date': ('就诊日期', 5),
            'doctor_name': ('医生签名', 5),
        }
        
        # 检查必填字段
        for field, (field_name, deduction) in required_fields.items():
            value = record_data.get(field)
            if not value or (isinstance(value, list) and len(value) == 0):
                issues.append({
                    'issue_type': IssueType.COMPLETENESS,
                    'severity': IssueSeverity.CRITICAL,
                    'field_name': field_name,
                    'issue_description': f"缺少必填字段：{field_name}",
                    'suggestion': f"请完善{field_name}信息",
                    'score_deduction': deduction
                })
                score -= deduction
        
        # 检查重要字段
        for field, (field_name, deduction) in important_fields.items():
            value = record_data.get(field)
            if not value:
                issues.append({
                    'issue_type': IssueType.COMPLETENESS,
                    'severity': IssueSeverity.MAJOR,
                    'field_name': field_name,
                    'issue_description': f"缺少重要字段：{field_name}",
                    'suggestion': f"建议补充{field_name}信息",
                    'score_deduction': deduction
                })
                score -= deduction
        
        # 检查用药信息
        raw_data = record_data.get('raw_data', {})
        medications = raw_data.get('用药信息', [])
        if not medications or len(medications) == 0:
            issues.append({
                'issue_type': IssueType.COMPLETENESS,
                'severity': IssueSeverity.MINOR,
                'field_name': '用药信息',
                'issue_description': '未记录用药信息',
                'suggestion': '如有用药，请记录详细用药信息',
                'score_deduction': 5
            })
            score -= 5
        
        # 检查辅助检查
        if not record_data.get('auxiliary_exam') or record_data.get('auxiliary_exam') == '无。':
            issues.append({
                'issue_type': IssueType.COMPLETENESS,
                'severity': IssueSeverity.INFO,
                'field_name': '辅助检查',
                'issue_description': '未记录辅助检查结果',
                'suggestion': '建议记录相关检查结果（如有）',
                'score_deduction': 3
            })
            score -= 3
        
        return {
            'score': max(0, score),
            'issues': issues
        }
    
    def _evaluate_standardization(self, record_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        评估规范性（25%权重）
        检查格式、术语、书写规范
        """
        issues = []
        score = 100
        
        # 检查主诉长度（应简洁明了）
        chief_complaint = record_data.get('chief_complaint', '')
        if len(chief_complaint) > 100:
            issues.append({
                'issue_type': IssueType.STANDARDIZATION,
                'severity': IssueSeverity.MINOR,
                'field_name': '主诉',
                'issue_description': '主诉过长，应简洁明了',
                'suggestion': '主诉建议控制在50字以内，描述主要症状和时间',
                'score_deduction': 5
            })
            score -= 5
        
        # 检查现病史描述
        present_illness = record_data.get('present_illness', '')
        if present_illness and len(present_illness) < 20:
            issues.append({
                'issue_type': IssueType.STANDARDIZATION,
                'severity': IssueSeverity.MAJOR,
                'field_name': '现病史',
                'issue_description': '现病史描述过于简单',
                'suggestion': '现病史应详细描述发病时间、主要症状、伴随症状、就诊经过等',
                'score_deduction': 10
            })
            score -= 10
        
        # 检查诊断格式
        diagnosis = record_data.get('diagnosis', [])
        if diagnosis:
            for diag in diagnosis:
                # 检查是否有疑问诊断的标记
                if '?' in diag and '疑' not in diag and '待' not in diag:
                    issues.append({
                        'issue_type': IssueType.STANDARDIZATION,
                        'severity': IssueSeverity.INFO,
                        'field_name': '诊断',
                        'issue_description': f'诊断 "{diag}" 含有不确定性标记',
                        'suggestion': '不确定诊断建议使用"疑诊"或"待查"等规范用语',
                        'score_deduction': 3
                    })
                    score -= 3
        
        # 检查体格检查格式
        physical_exam = record_data.get('physical_exam', '')
        if physical_exam:
            # 应包含生命体征
            vital_signs = ['T', 'P', 'R', 'BP']
            missing_signs = [sign for sign in vital_signs if sign not in physical_exam]
            if len(missing_signs) > 0:
                issues.append({
                    'issue_type': IssueType.STANDARDIZATION,
                    'severity': IssueSeverity.MAJOR,
                    'field_name': '体格检查',
                    'issue_description': f'体格检查缺少生命体征: {", ".join(missing_signs)}',
                    'suggestion': '体格检查应完整记录T(体温)、P(脉搏)、R(呼吸)、BP(血压)',
                    'score_deduction': 8
                })
                score -= 8
        
        # 检查过敏史
        allergy_history = record_data.get('allergy_history', '')
        if allergy_history and '药物' not in allergy_history and '过敏' not in allergy_history:
            issues.append({
                'issue_type': IssueType.STANDARDIZATION,
                'severity': IssueSeverity.MINOR,
                'field_name': '过敏史',
                'issue_description': '过敏史书写不规范',
                'suggestion': '过敏史应明确说明"否认药物过敏史"或"有XX药物过敏史"',
                'score_deduction': 5
            })
            score -= 5
        
        return {
            'score': max(0, score),
            'issues': issues
        }
    
    def _evaluate_consistency(self, record_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        评估一致性（25%权重）
        检查诊断与症状、用药与诊断的一致性
        """
        issues = []
        score = 100
        
        diagnosis = record_data.get('diagnosis', [])
        chief_complaint = record_data.get('chief_complaint', '').lower()
        present_illness = record_data.get('present_illness', '').lower()
        raw_data = record_data.get('raw_data', {})
        medications = raw_data.get('用药信息', [])
        
        # 简单的疾病-症状关键词映射
        disease_symptom_map = {
            '痛风': ['肿痛', '关节痛', '红肿'],
            '胃炎': ['胃痛', '腹痛', '恶心', '呕吐'],
            '高血压': ['头痛', '头晕', '血压'],
            '糖尿病': ['多饮', '多尿', '多食', '消瘦'],
        }
        
        # 检查诊断与症状的一致性
        for diag in diagnosis:
            matched = False
            for disease, symptoms in disease_symptom_map.items():
                if disease in diag:
                    # 检查是否有相关症状
                    if any(symptom in chief_complaint or symptom in present_illness for symptom in symptoms):
                        matched = True
                        break
            
            if not matched and any(disease in diag for disease in disease_symptom_map.keys()):
                issues.append({
                    'issue_type': IssueType.CONSISTENCY,
                    'severity': IssueSeverity.MAJOR,
                    'field_name': '诊断一致性',
                    'issue_description': f'诊断 "{diag}" 与主诉/现病史描述的症状可能不一致',
                    'suggestion': '请检查诊断是否有充分的症状依据',
                    'score_deduction': 10
                })
                score -= 10
        
        # 检查用药与诊断的一致性
        if '痛风' in str(diagnosis):
            # 检查是否有痛风相关用药
            gout_meds = ['秋水仙碱', '别嘌醇', '非布司他', '碳酸氢钠']
            has_gout_med = any(
                any(med_name in medication.get('名称', '') for med_name in gout_meds)
                for medication in medications
            )
            if not has_gout_med:
                issues.append({
                    'issue_type': IssueType.CONSISTENCY,
                    'severity': IssueSeverity.MAJOR,
                    'field_name': '用药一致性',
                    'issue_description': '诊断为痛风但未见典型的痛风治疗药物',
                    'suggestion': '痛风治疗通常需要秋水仙碱、别嘌醇等药物',
                    'score_deduction': 8
                })
                score -= 8
        
        # 检查时间逻辑
        visit_date = record_data.get('visit_date')
        if visit_date:
            # 检查主诉中的时间是否超过就诊日期
            time_pattern = r'(\d+)\s*([天日月年周])'
            time_matches = re.findall(time_pattern, chief_complaint)
            if time_matches:
                # 简单检查，不进行复杂的日期计算
                pass
        
        return {
            'score': max(0, score),
            'issues': issues
        }
    
    def _evaluate_accuracy(self, record_data: Dict[str, Any]) -> Dict[str, Any]:
        """
        评估准确性（20%权重）
        检查数值范围、逻辑合理性
        """
        issues = []
        score = 100
        
        # 检查年龄合理性
        age = record_data.get('patient_age')
        if age is not None:
            if age < 0 or age > 150:
                issues.append({
                    'issue_type': IssueType.ACCURACY,
                    'severity': IssueSeverity.CRITICAL,
                    'field_name': '患者年龄',
                    'issue_description': f'年龄数值异常: {age}岁',
                    'suggestion': '请检查年龄是否正确',
                    'score_deduction': 15
                })
                score -= 15
        
        # 检查体格检查中的生命体征
        physical_exam = record_data.get('physical_exam', '')
        
        # 体温检查
        temp_match = re.search(r'T\s*(\d+\.?\d*)\s*[℃°C]', physical_exam)
        if temp_match:
            temp = float(temp_match.group(1))
            if temp < 35.0 or temp > 42.0:
                issues.append({
                    'issue_type': IssueType.ACCURACY,
                    'severity': IssueSeverity.MAJOR,
                    'field_name': '体温',
                    'issue_description': f'体温数值异常: {temp}℃',
                    'suggestion': '正常体温范围: 36.0-37.5℃，请检查数值',
                    'score_deduction': 10
                })
                score -= 10
        
        # 脉搏检查
        pulse_match = re.search(r'P\s*(\d+)\s*次', physical_exam)
        if pulse_match:
            pulse = int(pulse_match.group(1))
            if pulse < 40 or pulse > 200:
                issues.append({
                    'issue_type': IssueType.ACCURACY,
                    'severity': IssueSeverity.MAJOR,
                    'field_name': '脉搏',
                    'issue_description': f'脉搏数值异常: {pulse}次/分',
                    'suggestion': '正常脉搏范围: 60-100次/分，请检查数值',
                    'score_deduction': 8
                })
                score -= 8
        
        # 血压检查
        bp_match = re.search(r'BP?\s*(\d+)/(\d+)\s*mmHg', physical_exam, re.IGNORECASE)
        if bp_match:
            systolic = int(bp_match.group(1))
            diastolic = int(bp_match.group(2))
            if systolic < 60 or systolic > 250 or diastolic < 40 or diastolic > 150:
                issues.append({
                    'issue_type': IssueType.ACCURACY,
                    'severity': IssueSeverity.MAJOR,
                    'field_name': '血压',
                    'issue_description': f'血压数值异常: {systolic}/{diastolic}mmHg',
                    'suggestion': '请检查血压数值是否正确',
                    'score_deduction': 8
                })
                score -= 8
        
        # 检查用药剂量合理性（简单检查）
        raw_data = record_data.get('raw_data', {})
        medications = raw_data.get('用药信息', [])
        for med in medications:
            duration_str = str(med.get('天数', ''))
            duration_match = re.search(r'(\d+)', duration_str)
            if duration_match:
                duration = int(duration_match.group(1))
                if duration > 30:
                    issues.append({
                        'issue_type': IssueType.ACCURACY,
                        'severity': IssueSeverity.MINOR,
                        'field_name': '用药天数',
                        'issue_description': f'药物 "{med.get("名称", "")}" 用药天数过长: {duration}天',
                        'suggestion': '门诊用药一般不超过14天，请确认是否正确',
                        'score_deduction': 5
                    })
                    score -= 5
        
        return {
            'score': max(0, score),
            'issues': issues
        }
    
    def _generate_summary(self, overall_score: int, issues: List[Dict]) -> str:
        """生成评估总结"""
        if overall_score >= 90:
            quality = "优秀"
            comment = "病历质量整体优秀，符合规范要求。"
        elif overall_score >= 80:
            quality = "良好"
            comment = "病历质量良好，存在少量问题需要改进。"
        elif overall_score >= 70:
            quality = "中等"
            comment = "病历质量中等，存在一些需要完善的地方。"
        elif overall_score >= 60:
            quality = "及格"
            comment = "病历质量勉强及格，建议重点改进关键问题。"
        else:
            quality = "不及格"
            comment = "病历质量不达标，存在严重问题，需要全面整改。"
        
        critical_count = sum(1 for issue in issues if issue['severity'] == IssueSeverity.CRITICAL)
        major_count = sum(1 for issue in issues if issue['severity'] == IssueSeverity.MAJOR)
        
        summary = f"病历质量评估等级：{quality}（{overall_score}分）。{comment}"
        if critical_count > 0:
            summary += f" 发现{critical_count}个严重问题。"
        if major_count > 0:
            summary += f" 发现{major_count}个主要问题。"
        
        return summary
    
    def _generate_suggestions(self, issues: List[Dict]) -> List[str]:
        """生成改进建议"""
        suggestions = []
        
        # 按严重程度排序
        sorted_issues = sorted(
            issues,
            key=lambda x: {
                IssueSeverity.CRITICAL: 0,
                IssueSeverity.MAJOR: 1,
                IssueSeverity.MINOR: 2,
                IssueSeverity.INFO: 3
            }[x['severity']]
        )
        
        # 提取前5个最重要的建议
        for issue in sorted_issues[:5]:
            if issue.get('suggestion'):
                suggestions.append(issue['suggestion'])
        
        # 如果没有问题，给予鼓励
        if len(suggestions) == 0:
            suggestions.append("病历质量优秀，请继续保持！")
        
        return suggestions

